package com.sina.finance.api.sdk;


import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;

public class DefaultApiClient implements ApiClient {
    private static final String APP_KEY = "app_key";
    private static final String FORMAT = "format";
    private static final String METHOD = "method";
    private static final String TIMESTAMP = "timestamp";
    private static final String SIGN = "sign";
    private static final String SESSION = "session";
    private String serverUrl;
    private String appKey;
    private String appSecret;
    private String format = "xml";
    private String signMethod = Constants.SIGN_METHOD_MD5;

    private int connectTimeout = 0;
    private int readTimeout = 0;

    private Boolean needCheckRequest = Boolean.valueOf(true);

    public DefaultApiClient(String serverUrl, String appKey, String appSecret) {
        this.serverUrl = serverUrl;
        this.appKey = appKey;
        this.appSecret = appSecret;
    }

    public DefaultApiClient(String serverUrl, String appKey, String appSecret, String format) {
        this(serverUrl, appKey, appSecret);
        this.format = format;
    }

    public DefaultApiClient(String serverUrl, String appKey, String appSecret, String format, int connectTimeout, int readTimeout) {
        this(serverUrl, appKey, appSecret, format);
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
    }

    public DefaultApiClient(String paramString1, String paramString2, String paramString3, String paramString4, int paramInt1, int paramInt2, String paramString5) {
        this(paramString1, paramString2, paramString3, paramString4, paramInt1, paramInt2);
        this.signMethod = paramString5;
    }

    public String execute(ApiRequest apiRequest) throws ApiException {
        return execute(apiRequest, null);
    }

    public String execute(ApiRequest apiRequest, String charset) throws ApiException {
        return _execute(apiRequest, charset);
    }

    private String _execute(ApiRequest apiRequest, String charset) throws ApiException {

        if (this.needCheckRequest.booleanValue() == true) {
            try {
                apiRequest.check();
            } catch (ApiRuleException apiRuleE) {
                throw apiRuleE;
            }
        }

        return doPost(apiRequest, charset);
    }

    private String doPost(ApiRequest request, String paramString)
            throws ApiException {

        RequestParametersHolder requestParametersHolder = configRequestParams(request);

         StringBuffer fullRequestUrl = configUrl(paramString, requestParametersHolder);

        String response = null;

        response = WebUtils.doPost(fullRequestUrl.toString(), requestParametersHolder.getApplicationParams(), this.connectTimeout, this.readTimeout);

        return response;
    }

    private StringBuffer configUrl(String paramString, RequestParametersHolder requestParametersHolder) {

        StringBuffer fullRequestUrl = new StringBuffer(this.serverUrl);

        fullRequestUrl.append("?");
        fullRequestUrl.append(requestParametersHolder.getSerializedParams());
        return fullRequestUrl;
    }

    private RequestParametersHolder configRequestParams(ApiRequest paramRopRequest) {
        RequestParametersHolder requestParametersHolder = new RequestParametersHolder();

        /**
         * 设置业务相关的参数
         */
        requestParametersHolder.setApplicationParams(new ApiHashMap(paramRopRequest.getTextParams()));

        /**
         * 设置框架协议中必须的参数
         */
        requestParametersHolder.addProtocalMustParams("method", paramRopRequest.getApiMethodName());
        requestParametersHolder.addProtocalMustParams("app_key", this.appKey);

        Long localLong = Long.valueOf(new Date().getTime());
        SimpleDateFormat localSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        localSimpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        //requestParametersHolder.addProtocalMustParams("timestamp", localSimpleDateFormat.format(new Date(localLong.longValue())));
        //20160201 之前框架中传入的是格式化的日期格式, 目前认为直接传入时间戳就可以
        requestParametersHolder.addProtocalMustParams("timestamp", new Date().getTime() + "");


        /**
         * 设置框架协议可选参数
         */
        requestParametersHolder.addProtocalOptParams("format", this.format);

        try {
            if (Constants.SIGN_METHOD_MD5.equals(this.signMethod)) {
                requestParametersHolder.addProtocalMustParams("sign", this.sign(requestParametersHolder, this.appSecret));
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }

        return requestParametersHolder;
    }

    public static String sign(RequestParametersHolder paramRequestParametersHolder, String appSecret)
            throws IOException {
        TreeMap localTreeMap = new TreeMap(new MapComparator());

        ApiHashMap localRopHashMap1 = paramRequestParametersHolder.getApplicationParams();
        if ((localRopHashMap1 != null) && (localRopHashMap1.size() > 0)) {
            localTreeMap.putAll(localRopHashMap1);
        }
        ApiHashMap localRopHashMap2 = paramRequestParametersHolder.getProtocalMustParams();
        if ((localRopHashMap2 != null) && (localRopHashMap2.size() > 0)) {
            localTreeMap.putAll(localRopHashMap2);
        }
        ApiHashMap localRopHashMap3 = paramRequestParametersHolder.getProtocalOptParams();
        if ((localRopHashMap3 != null) && (localRopHashMap3.size() > 0)) {
            localTreeMap.putAll(localRopHashMap3);
        }
        Set localSet = localTreeMap.entrySet();

        StringBuilder localStringBuilder = new StringBuilder(appSecret);

        for (Object localObject = localSet.iterator(); ((Iterator) localObject).hasNext(); ) {
            Map.Entry localEntry = (Map.Entry) ((Iterator) localObject).next();
            if (StringUtils.areNotEmpty(new String[]{(String) localEntry.getKey(), (String) localEntry.getValue()})) {
                localStringBuilder.append((String) localEntry.getKey()).append((String) localEntry.getValue());
            }

        }

        localStringBuilder.append(appSecret);
        byte[] encrypted = encryptMD5(localStringBuilder.toString());

        return byte2hex((byte[]) encrypted);
    }

    private static String byte2hex(byte[] paramArrayOfByte) {
        StringBuilder localStringBuilder = new StringBuilder();
        for (int i = 0; i < paramArrayOfByte.length; i++) {
            String str = Integer.toHexString(paramArrayOfByte[i] & 0xFF);
            if (str.length() == 1) {
                localStringBuilder.append("0");
            }
            localStringBuilder.append(str.toUpperCase());
        }
        return localStringBuilder.toString();
    }

    private static byte[] encryptMD5(String paramString) throws IOException {
        byte[] arrayOfByte = null;
        try {
            MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
            arrayOfByte = localMessageDigest.digest(paramString.getBytes("UTF-8"));
        } catch (GeneralSecurityException localGeneralSecurityException) {
            throw new IOException(localGeneralSecurityException);
        }
        return arrayOfByte;
    }
}
